{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Itertools jupyter notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### What are iterables?\n",
    "\n",
    "The Python itertools module is a collection of tools for handling iterators. Simply put, iterators are data types that can be used in a for loop. The most common iterator in Python is the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n"
     ]
    }
   ],
   "source": [
    "for each in colors:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Requirements\n",
    "\n",
    "We must import the itertools module before we can use it. We will also import the operator module. This module is not necessary when using itertools, it is only needed for some of the examples below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import itertools\n",
    "import operator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Itertools Module\n",
    "\n",
    "This module is a collection of functions. We are going to explore each one of these function. If you have any questions, suggestion, or correction, please put them in the comments below. I address them as soon as possible."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### accumulate()\n",
    "\n",
    "`itertools.accumulate(iterable[, func])`\n",
    "\n",
    "This function makes an iterator that returns the results of a function. Functions can be passed around very much like variables. The accumulate() function takes a function as an argument. It also takes an iterable. It returns the accumulated results. The results are themselves contained in an iterable. This may all sound very confusing. I assure you that, when you play with the code it will make sense."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "6\n",
      "24\n",
      "120\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "'''accumulate() '''\n",
    "data = [1, 2, 3, 4, 5]\n",
    "result = itertools.accumulate(data, operator.mul)\n",
    "for each in result:\n",
    "    print(each)\n",
    "print('\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### combinations()\n",
    "\n",
    "`itertools.combinations(iterable, r)`\n",
    "\n",
    "This function takes an iterable and a integer. This will create all the unique combination that have r members.\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('circle', 'triangle')\n",
      "('circle', 'square')\n",
      "('triangle', 'square')\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "shapes = ['circle', 'triangle', 'square',]\n",
    "\n",
    "result = itertools.combinations(shapes, 2)\n",
    "\n",
    "for each in result:\n",
    "    print(each)\n",
    "print('\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### combinations_with_replacement()\n",
    "\n",
    "`itertools.combinations_with_replacement(iterable, r)`\n",
    "\n",
    "This one is just like the combinations() function, but this one allows individual elements to be repeated more than once."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('circle', 'circle')\n",
      "('circle', 'triangle')\n",
      "('circle', 'square')\n",
      "('triangle', 'triangle')\n",
      "('triangle', 'square')\n",
      "('square', 'square')\n"
     ]
    }
   ],
   "source": [
    "shapes = ['circle', 'triangle', 'square',]\n",
    "\n",
    "result = itertools.combinations_with_replacement(shapes, 2)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### count()\n",
    "\n",
    "`itertools.count(start=0, step=1)`\n",
    "\n",
    "Makes an iterator that returns evenly spaced values starting with number start."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "13\n",
      "16\n",
      "19\n",
      "22\n"
     ]
    }
   ],
   "source": [
    "for i in itertools.count(10,3):\n",
    "    print(i)\n",
    "    if i > 20:\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### cycle()\n",
    "\n",
    "`itertools.cycle(iterable)`\n",
    "\n",
    "This function cycles through an iterator endlessly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n",
      "blue\n",
      "violet\n",
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n",
      "blue\n",
      "violet\n",
      "red\n",
      "orange\n",
      "yellow\n"
     ]
    }
   ],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet']\n",
    "num_cycle = 3*5\n",
    "for color in itertools.cycle(colors):\n",
    "    if num_cycle == 0:\n",
    "        break;\n",
    "    print(color)\n",
    "    num_cycle = num_cycle -1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### chain()\n",
    "\n",
    "`itertools.chain(*iterables)`\n",
    "\n",
    "This function takes a series of iterables and return them as one long iterable.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n",
      "blue\n",
      "circle\n",
      "triangle\n",
      "square\n",
      "pentagon\n"
     ]
    }
   ],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green', 'blue']\n",
    "shapes = ['circle', 'triangle', 'square', 'pentagon']\n",
    "\n",
    "result = itertools.chain(colors, shapes)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### compress()\n",
    "\n",
    "``itertools.compress(data, selectors)``\n",
    "\n",
    "This function filters one iterable with another."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "circle\n",
      "square\n"
     ]
    }
   ],
   "source": [
    "shapes = ['circle', 'triangle', 'square', 'pentagon']\n",
    "selections = [True, False, True, False]\n",
    "\n",
    "result = itertools.compress(shapes, selections)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### dropwhile()\n",
    "\n",
    "`itertools.dropwhile(predicate, iterable)`\n",
    "\n",
    "Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1]\n",
    "\n",
    "result = itertools.dropwhile(lambda x: x<5, data)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### filterfalse()\n",
    "\n",
    "`itertools.filterfalse(predicate, iterable)`\n",
    "\n",
    "This function makes an iterator that filters elements from iterable returning only those for which the predicate is False."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "result = itertools.filterfalse(lambda x: x<5, data)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### groupby()\n",
    "\n",
    "`itertools.groupby(iterable, key=None)`\n",
    "\n",
    "Simply put, this function groups things together. Ok. This one is complicated. And the example is a bit long."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "autobot\n",
      "[{'name': 'blaster', 'faction': 'autobot'}]\n",
      "decepticon\n",
      "[{'name': 'galvatron', 'faction': 'decepticon'}]\n",
      "autobot\n",
      "[{'name': 'jazz', 'faction': 'autobot'}, {'name': 'metroplex', 'faction': 'autobot'}]\n",
      "decepticon\n",
      "[{'name': 'megatron', 'faction': 'decepticon'}, {'name': 'starcream', 'faction': 'decepticon'}]\n"
     ]
    }
   ],
   "source": [
    "robots = [{\n",
    "    'name': 'blaster',\n",
    "    'faction': 'autobot'\n",
    "}, {\n",
    "    'name': 'galvatron',\n",
    "    'faction': 'decepticon'\n",
    "}, {\n",
    "    'name': 'jazz',\n",
    "    'faction': 'autobot'\n",
    "}, {\n",
    "    'name': 'metroplex',\n",
    "    'faction': 'autobot'\n",
    "}, {\n",
    "    'name': 'megatron',\n",
    "    'faction': 'decepticon'\n",
    "}, {\n",
    "    'name': 'starcream',\n",
    "    'faction': 'decepticon'\n",
    "}]\n",
    "\n",
    "for key, group in itertools.groupby(robots, key=lambda x: x['faction']):\n",
    "    print(key)\n",
    "    print(list(group))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### islice()\n",
    "\n",
    "`itertools.islice(iterable, start, stop[, step])`\n",
    "\n",
    "This function is very much like slices. This function allows you to cut out a piece of an iterable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "red\n",
      "orange\n"
     ]
    }
   ],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green', 'blue',]\n",
    "few_colors = itertools.islice(colors, 2)\n",
    "for each in few_colors:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('a', 'b', 'c')\n",
      "('a', 'c', 'b')\n",
      "('b', 'a', 'c')\n",
      "('b', 'c', 'a')\n",
      "('c', 'a', 'b')\n",
      "('c', 'b', 'a')\n"
     ]
    }
   ],
   "source": [
    "#permutations()\n",
    "\n",
    "alpha_data = ['a', 'b', 'c']\n",
    "\n",
    "result = itertools.permutations(alpha_data)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### product()\n",
    "\n",
    "This function creates the cartesian products from a series of iterables.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 'a')\n",
      "(1, 'b')\n",
      "(1, 'c')\n",
      "(2, 'a')\n",
      "(2, 'b')\n",
      "(2, 'c')\n",
      "(3, 'a')\n",
      "(3, 'b')\n",
      "(3, 'c')\n"
     ]
    }
   ],
   "source": [
    "num_data = [1, 2, 3]\n",
    "alpha_data = ['a', 'b', 'c']\n",
    "\n",
    "result = itertools.product(num_data, alpha_data)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### repeat()\n",
    "\n",
    "`itertools.repeat(object[, times])`\n",
    "\n",
    "This function will repeat an object over and over again. Unless, there is a times argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n"
     ]
    }
   ],
   "source": [
    "repeat = 10\n",
    "for i in itertools.repeat(\"spam\"):\n",
    "    if repeat == 0:\n",
    "        break\n",
    "    print(i)\n",
    "    repeat = repeat - 1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n",
      "spam\n"
     ]
    }
   ],
   "source": [
    "for i in itertools.repeat(\"spam\",10):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### starmap()\n",
    "\n",
    "`itertools.starmap(function, iterable)`\n",
    "\n",
    "This function makes an iterator that computes the function using arguments obtained from the iterable. Let us take a looky."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12\n",
      "32\n",
      "21\n"
     ]
    }
   ],
   "source": [
    "data = [(2, 6), (8, 4), (7, 3)]\n",
    "result = itertools.starmap(operator.mul, data)\n",
    "for each in result:\n",
    "    print(each)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### takewhile()\n",
    "\n",
    "`itertools.takwwhile(predicate, iterable)`\n",
    "\n",
    "This is kind of the opposite of `dropwhile()`. This function makes an iterator and returns elements from the iterable as long as the predicate is true."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1]\n",
    "\n",
    "result = itertools.takewhile(lambda x: x<5, data)\n",
    "for each in result:\n",
    "    print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### tee()\n",
    "\n",
    "`itertools.tee(iterable, n=2)`\n",
    "\n",
    "Return n independent iterators from a single iterable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n",
      "blue\n",
      "..\n",
      "red\n",
      "orange\n",
      "yellow\n",
      "green\n",
      "blue\n"
     ]
    }
   ],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green', 'blue']\n",
    "alpha_colors, beta_colors = itertools.tee(colors)\n",
    "\n",
    "for each in alpha_colors:\n",
    "    print(each)\n",
    "\n",
    "print('..')\n",
    "\n",
    "for each in beta_colors:\n",
    "     print(each)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### zip_longest()\n",
    "\n",
    "`itertools.zip_longest(*iterables, fillvalue=None)`\n",
    "\n",
    "This function makes an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('red', 1)\n",
      "('orange', 2)\n",
      "('yellow', 3)\n",
      "('green', 4)\n",
      "('blue', 5)\n",
      "(None, 6)\n",
      "(None, 7)\n",
      "(None, 8)\n",
      "(None, 9)\n",
      "(None, 10)\n"
     ]
    }
   ],
   "source": [
    "colors = ['red', 'orange', 'yellow', 'green', 'blue',]\n",
    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,]\n",
    "\n",
    "for each in itertools.zip_longest(colors, data, fillvalue=None):\n",
    "    print(each)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
